const { Command } = require('commander');
const createFileClient = require('./file-client');
const readline = require('readline');

const state = {
    program: new Command(),
    client: null,
    rl: null,
    host:null,
    port:null,
    user:null
}

function initReadline() {
    state.rl = readline.createInterface({
        input: process.stdin,
        output: process.stdout
    });
}

// 验证IP地址格式的函数，简单判断是否符合常见的IPv4格式，可根据实际需求进一步完善
function isValidIP(ip) {
    const ipPattern = /^(\d{1,3}\.){3}\d{1,3}$/;
    if (!ipPattern.test(ip)) {
        return false;
    }
    const parts = ip.split('.');
    for (const part of parts) {
        const num = parseInt(part, 10);
        if (num < 0 || num > 255) {
            return false;
        }
    }
    return true;
}


function initProgram() {
    
    const args = process.argv.slice(2); // 获取除了命令本身（node index.js）之外的参数
    if (args.some(arg => arg === '--help')) {
        showAvailableCommands();
        process.exit(0);
    }
    // 用于存储解析后的参数对象
    const parsedArgs = {};
    for (let i = 0; i < args.length; i++) {
        const arg = args[i];
        if (arg.startsWith('--host=')) {
            const hostValue = arg.split('=')[1];
            if (!isValidIP(hostValue)) {
                console.error('--host参数后的值格式错误，请输入合法的IP地址格式，例如：192.168.0.1');
                process.exit(1);
            }
            parsedArgs.host = hostValue;
        } else if (arg.startsWith('--port=')) {
            const portValue = arg.split('=')[1];
            const portNum = parseInt(portValue, 10);
            if (!(portValue === portNum.toString())||isNaN(portValue) || portValue < 0 || portValue > 65535) {
                console.error('--port参数后的值格式错误，请输入合法的端口号（范围是0 - 65535的整数）');
                process.exit(1);
            }
            parsedArgs.port = portValue;
        } else if (arg.startsWith('--user=')) {
            parsedArgs.user = arg.split('=')[1];
        } else if (arg.startsWith('--pwd=')) {
            parsedArgs.pwd = arg.split('=')[1];
        }
    }

    // 检查用户和密码是否同时存在
    if ((parsedArgs.user &&!parsedArgs.pwd) || (!parsedArgs.user && parsedArgs.pwd)) {
        console.error('--user和--pwd必须同时出现，请检查输入参数');
        process.exit(1);
    }

    // 获取各参数值，若不存在则使用默认值，并进行空格清理等处理
    const host = (parsedArgs.host || '').trim() || '127.0.0.1';
    const port = (parsedArgs.port || '').trim() || '8080';
    const user = (parsedArgs.user || '').trim() || 'zs';
    const pwd = (parsedArgs.pwd || '').trim() || 'ddd';


    // 检查用户和密码是否同时存在
    state.program
        .option('--host <host>', 'server host', host)
        .option('--port <port>', 'server port', port)
        .option('--user <username>', 'username', user || 'zs')
        .option('--pwd <password>', 'password', pwd || 'ddd');

    initCommands();
}

function initCommands() {
    // 文件操作命令
    state.program
        .command('upload <file>')
        .description('Upload a file to server')
        .action(handleCommand(async (file) => {
            const result = await state.client.uploadFile(file);
            console.log(result);
        }));

    state.program
        .command('download <file>')
        .description('Download a file from server')
        .action(handleCommand(async (file) => {
            const result = await state.client.downloadFile(file);
            console.log(result);
        }));

    state.program
        .command('delete <name>')
        .description('Delete a file or directory')
        .action(handleCommand(async (name) => {
            const result = await state.client.deleteItem(name);
            console.log(result);
        }));

    state.program
        .command('rename <old> <new>')
        .description('Rename a file or directory')
        .action(handleCommand(async (oldName, newName) => {
            const result = await state.client.renameItem(oldName, newName);
            console.log(result);
        }));

    // 目录操作命令
    state.program
        .command('mkdir <name>')
        .description('Create a new directory')
        .action(handleCommand(async (name) => {
            const result = await state.client.createDirectory(name);
            console.log(result);
        }));

    state.program
        .command('list')
        .description('List current directory contents')
        .action(handleCommand(async () => {
            const files = await state.client.listFiles();
            console.log('\n当前服务器目录下的内容有:');
            console.log('-------------------------------');
            files.forEach(file => {
                console.log(`${file.name}${file.isDir ? '/' : ''}`);
            });
            console.log('-------------------------------');
        }));

    // 目录导航命令
    state.program
        .command('lcd <path>')
        .description('Change local directory')
        .action(handleCommand(async (path) => {
            const result = await state.client.changeLocalDir(path);
            console.log(result);
        }));

    state.program
        .command('lpwd')
        .description('Print local working directory')
        .action(handleCommand(() => {
            console.log('Local directory:', state.client.getLocalDir());
        }));

    state.program
        .command('rcd <path>')
        .description('Change remote directory')
        .action(handleCommand(async (path) => {
            const result = await state.client.changeRemoteDir(path);
            console.log(result);
        }));

    state.program
        .command('rpwd')
        .description('Print remote working directory')
        .action(handleCommand(() => {
            console.log('Remote directory:', state.client.getRemoteDir());
        }));
}

async function promptForOptions() {
    console.log('正在与ftp系统进行连接');
    console.log('--------------------------------------------------------------------------------');
    
    const options = state.program.opts(); // 获取默认选项

    try {
        state.client = createFileClient({
            apiUrl: 'http://127.0.0.1:8080',
            username: options.user,
            password: options.pwd
        });
        state.host=options.host;
        state.port=options.port;
        state.user=options.user;
        
        let login_res=await state.client.login();
        if(login_res.ok){
            console.log('\n登录成功！以下为客户端信息:');
            showClientInfo();
            // console.log('\n以下为可用的指令:');
            // showAvailableCommands();
            
            // 切换到命令模式
            state.rl.setPrompt('ftp> ');
            state.rl.prompt();
            setupCommandListener();
        }else{
            console.log('登录失败，请检查用户名与密码是否正确');
            console.log('\n请重新尝试登录！')
            process.exit(1);
        }
    } catch (error) {
        console.error('登录失败:', error.message);
        process.exit(1);
    }
}

function question(query, defaultValue) {
    return new Promise((resolve) => {
        state.rl.question(query, (answer) => {
            resolve(answer.trim() || defaultValue);
        });
    });
}

function showClientInfo(){
    console.log(`
        当前客户端信息:
        --host:     -${state.host}
        --port:     -${state.port}
        --user:     -${state.user}
      `);

}

function showAvailableCommands() {
    console.log(`
      客户端命令和参数使用指南:
      upload <file>     -上传本地当前目录的文件到服务器的当前目录
      download <file>   -下载服务器当前目录的文件到本地当前目录
      delete <file>     -删除服务器当前目录的文件
      rename <file-old> <file-new> -修改服务器当前目录的文件名
      mkdir <dir>       -在服务器当前目录，创建子目录
      delete <dir>      -删除服务器当前目录下的子目录，支持递归删除
      rename <dir-old> <dir-new>       -修改服务器当前目录下的子目录名称
      list              -查看服务器当前目录下的文件或目录，目录名后面加/
      lcd <dir>         -修改本地当前目录，仅支持绝对路径
      lpwd              -打印本地当前目录的绝对路径
      rcd <dir>         -修改服务器当前目录，仅支持绝对路径
      rpwd              -打印服务器当前目录的绝对路径
      --help            -展示此条帮助信息
      exit              -退出系统
    `);
}

function setupCommandListener() {
    state.rl.on('line', async (line) => {
        if (line.trim()) {
            if (line.trim() === 'exit') {
                console.log('谢谢使用，下次再见！');
                process.exit(0);
            } else if (line.trim() === '--help') {
                showAvailableCommands();
            } else {
                try {
                    await state.program.parseAsync(['node', 'index.js', ...line.trim().split(' ')]);
                } catch (err) {
                    console.error('命令行错误:', err.message);
                }
            }
        }
        state.rl.prompt();
    });

    state.rl.on('close', () => {
        console.log('\n谢谢使用，下次再见！');
        process.exit(0);
    });
}

function handleCommand(fn) {
    return async (...args) => {
        try {
            await fn(...args);
        } catch (error) {
            console.error('Error:', error.message);
        }
    };
}

async function start() {
    initProgram();
    initReadline();
    await promptForOptions();
}

module.exports = { start };